package com.guli.gulimall.search.thread;

import java.util.Random;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public class ThreadTests {
    private static ExecutorService service = Executors.newFixedThreadPool(5);

    public static void main(String[] args) throws Exception {
//        runAsync();
//        CompletableFuture<Long> future = supplyAsync();
//        whenComplete();
//        thenApply();
//        handle();
//        thenAccept();
//        thenRun();
//        thenCombine();
//        thenAcceptBoth();
//        applyToEither();
        acceptEither();
        System.out.println("主线程执行完成");
    }

    //--------------------------任务普通操作----------------------------

    //runAsync无返回值
    public static CompletableFuture<Void> runAsync() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            System.out.println("run end ..."+Thread.currentThread().getId());
        },service);
//        future.get();
        return future;
    }

    //supplyAsync有返回值
    public static CompletableFuture<Long> supplyAsync() throws Exception {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            System.out.println("run end ...");
            return System.currentTimeMillis();
        });

        return future;
    }



    /**
     * whenCompleteAsync：方法完成后的感知
     * exceptionally    ：感知异常，可以修改返回结果
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void whenComplete() throws ExecutionException, InterruptedException {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("run start ...");
                TimeUnit.SECONDS.sleep(1);
                Long i = 1000L / 0;
            } catch (InterruptedException e) {
            }
            return 1L;
        },service).whenCompleteAsync((res,exception)->{
            System.out.println("结果完成"+res);
            System.out.println("出现异常:"+exception);
        }).exceptionally(t->{
            System.out.println(t.getMessage());
            return 10L;
        });
        System.out.println("run end ..." +future.get());
    }


    /**
     * handle:方法完成后的处理，修改并返回结果
     *
     * @throws Exception
     */
    private static void handle() throws Exception {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("run start ...");
                TimeUnit.SECONDS.sleep(1);
                Long i = 1000L / 0;
                return 1L;
            } catch (InterruptedException e) {
                return 2L;
            }
        }, service).handle((t,u)->{
            System.out.println(u.getMessage());
            return t * 2;
        });
        System.out.println(future.get());
    }


    // ------------------------任务串行化------------------------
    /**
     * 任务串行化
     * thenRun： 不能获取到上一步的结果
     * @throws Exception
     */
    private static void thenRun() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("run start ...");
                TimeUnit.SECONDS.sleep(1);
                Long i = 1000L / 0;
                return 1L;
            } catch (InterruptedException e) {
                e.printStackTrace();
                return -1L;
            }
        }, service).thenRun(() -> {
            System.out.println("thenRun方法执行了，，");
        });
        System.out.println(future.get());
    }

    /**
     * 任务串行化
     * thenAccept：能接收上一步的结果，但是无返回值。
     * @throws Exception
     */
    private static void thenAccept() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("run start ...");
                TimeUnit.SECONDS.sleep(1);
                Long i = 1000L / 3;
                return 1L;
            } catch (InterruptedException e) {
                return 2L;
            }
        }, service).thenAccept(res -> {
            System.out.println(res);
        });
//        System.out.println(future.get());
    }

    /**
     * 任务串行化
     * thenApply:能接收上一步的返回结果并且可以返回结果。
     * @throws Exception
     */
    private static void thenApply() throws Exception {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("run start ...");
                TimeUnit.SECONDS.sleep(1);
                Long i = 1000L / 3;
            } catch (InterruptedException e) {
            }
            return 1L;
        }, service).thenApply(res -> res * 2);
        System.out.println(future.get());
    }


    //-------------------------任务组合---------------------------


    /**
     * 任务组合
     * runAfterBothAsync: 不能获取到另外两个任务的执行结果。
     * thenAcceptBothAsync: 能获取到另外两个任务的执行结果，但是无法修改返回值。
     * @throws Exception
     */
    private static void thenAcceptBoth() throws Exception {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务1="+t);
            return t;
        },service);

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2="+t);
            return t;
        },service);

//        f1.runAfterBothAsync(f2,()->{
//            System.out.println("任务3开始。。。");
//        });
        f1.thenAcceptBothAsync(f2,(cf1,cf2)->{
            System.out.println("任务3开始----》 任务一：" + cf1 + "任务二：" + cf2);
        },service);
    }

    /**
     * 任务组合
     * thenCombine:既能接收其他两个任务的返回值，自己又能返回值结果。
     * @throws Exception
     */
    private static void thenCombine() throws Exception {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello1");
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "hello2");
        CompletableFuture<String> result = future1.thenCombine(future2, (f1, f2) -> f1+" "+f2);
        System.out.println(result.get());
    }

    //--------------------------单任务执行完成，执行该任务--------------------------

    /**
     * runAfterEitherAsync ：当两个任务中，有一个执行完成的时候。执行该任务。不接收值，无返回值。
     */
    private static void runAfterEitherAsync() throws Exception{
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1="+t);
            return t;
        },service);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2="+t);
            return t;
        },service);
        f1.runAfterEitherAsync(f2,()->{
            System.out.println("任务3开始执行、。。。");
        },service);
    }

    /**
     * acceptEither: 当两个任务中，有一个执行完成的时候，获取它的返回值，自己没有新的返回值。
     * @throws Exception
     */
    private static void acceptEither() throws Exception {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1="+t);
            return t;
        },service);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2="+t);
            return t;
        },service);

        CompletableFuture<Void> result = f1.acceptEither(f2, t -> {
            System.out.println("acceptEither:"+t);
        });

    }

    /**
     * applyToEither: 当两个任务中，有一个执行完成的时候，获取它的返回值,自己有新的返回值
     * @throws Exception
     */
    private static void applyToEither() throws Exception {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1="+t);
            return t;
        },service);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2="+t);
            return t;
        },service);

        CompletableFuture<Integer> result = f1.applyToEither(f2, t -> {
            System.out.println("applyEither:"+t);
            return t * 2;
        });

    }

    //-------------------------------多任务组合-------------------------------
    /**
     * allOf : 等待所有任务执行完成
     * @throws Exception
     */
    private static void allof() throws Exception{

        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1="+t);
            return t;
        },service);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2="+t);
            return t;
        },service);

        CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f3="+t);
            return t;
        },service);

        CompletableFuture<Void> allof = f1.allOf(f2, f3);
        allof.get();//等待所有结果完成
        System.out.println("执行完成 f1->"+f1.get() + "f2->"+f2.get() + "f3->"+f3.get());
    }

    /**
     *  anyOf：只要有一个成功就执行该任务
     * @throws Exception
     */
    public static void anyof() throws Exception{
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1="+t);
            return t;
        },service);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2="+t);
            return t;
        },service);
        CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> {
            int t = new Random().nextInt(3);
            try {
                TimeUnit.SECONDS.sleep(t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f3="+t);
            return t;
        },service);
        CompletableFuture<Object> anyof = f1.anyOf(f2, f3);
        System.out.println(anyof.get());
    }

}
